home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 15 / CU Amiga Magazine's Super CD-ROM 15 (1997)(EMAP Images)(GB)[!][issue 1997-10].iso / CUCD / Graphics / Ghostscript / source / gs_fonts.ps < prev    next >
Text File  |  1997-05-25  |  28KB  |  898 lines

  1. %    Copyright (C) 1990, 1995, 1996, 1997 Aladdin Enterprises.  All rights reserved.
  2. % This file is part of Aladdin Ghostscript.
  3. % Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  4. % or distributor accepts any responsibility for the consequences of using it,
  5. % or for whether it serves any particular purpose or works at all, unless he
  6. % or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  7. % License (the "License") for full details.
  8. % Every copy of Aladdin Ghostscript must include a copy of the License,
  9. % normally in a plain ASCII text file named PUBLIC.  The License grants you
  10. % the right to copy, modify and redistribute Aladdin Ghostscript, but only
  11. % under certain conditions described in the License.  Among other things, the
  12. % License requires that the copyright notice and this notice be preserved on
  13. % all copies.
  14.  
  15. % Font initialization and management code.
  16.  
  17. % Define the default font.
  18. /defaultfontname /Courier def
  19.  
  20. % Define the name of the font map file.
  21. /defaultfontmap (Fontmap) def
  22.  
  23. % ------ End of editable parameters ------ %
  24.  
  25. % Define a reliable way of accessing FontDirectory in systemdict.
  26. /.FontDirectory
  27. { //systemdict /FontDirectory get
  28. } bind odef
  29.  
  30. % If DISKFONTS is true, we load individual CharStrings as they are needed.
  31. % (This is intended primarily for machines with very small memories.)
  32. % In this case, we define another dictionary, parallel to FontDirectory,
  33. % that retains an open file for every font loaded.
  34. /FontFileDirectory 10 dict def
  35.  
  36. % Split up a search path into individual directories or files.
  37. /.pathlist        % <path> .pathlist <dir1|file1> ...
  38.  {  { dup length 0 eq { pop exit } if
  39.       .filenamelistseparator search not { exit } if
  40.       exch pop exch
  41.     }
  42.    loop
  43.  } bind def
  44.  
  45. % Load a font name -> font file name map.
  46. userdict /Fontmap .FontDirectory maxlength dict put
  47. /.loadFontmap        % <file> .loadFontmap -
  48.  {        % We would like to simply execute .definefontmap as we read,
  49.         % but we have to maintain backward compatibility with an older
  50.         % specification that makes later entries override earlier.
  51.    50 dict exch
  52.     { dup token not { closefile exit } if
  53.         % stack: <file> fontname
  54.       % This is a hack to get around the absurd habit of MS-DOS editors
  55.       % of adding an EOF character at the end of the file.
  56.       dup (\032) eq { pop closefile exit } if
  57.       1 index token not
  58.        { (Fontmap entry for ) print dup =only
  59.      ( has no associated file or alias name!  Giving up.\n) print flush
  60.      {.loadFontmap} 0 get 1 .quit
  61.        } if
  62.       dup type dup /stringtype eq exch /nametype eq or not
  63.        { (Fontmap entry for ) print 1 index =only
  64.      ( has an invalid file or alias name!  Giving up.\n) print flush
  65.      {.loadFontmap} 0 get 1 .quit
  66.        } if
  67.         % stack: dict file fontname filename|aliasname
  68.         % Read and pop tokens until a semicolon.
  69.        { 2 index token not
  70.       { (Fontmap entry for ) print 1 index =only
  71.         ( ends prematurely!  Giving up.\n) print flush
  72.         {.loadFontmap} 0 get 1 .quit
  73.       } if
  74.      dup /; eq { pop 3 index 3 1 roll .growput exit } if
  75.      pop
  76.        } loop
  77.     } loop
  78.     { .definefontmap } forall
  79.  } bind def
  80. % Add an entry in Fontmap.  We redefine this if the Level 2
  81. % resource machinery is loaded.
  82. /.definefontmap            % <fontname> <file|alias> .definefontmap -
  83.  {        % Since Fontmap is global, make sure the values are storable.
  84.    .currentglobal 3 1 roll true .setglobal
  85.    dup type /stringtype eq
  86.     { dup .gcheck not { dup length string copy } if
  87.     }
  88.    if
  89.    Fontmap 3 -1 roll 2 copy .knownget
  90.     {        % Add an element to the end of the existing value,
  91.         % unless it's the same as the current last element.
  92.       mark exch aload pop counttomark 4 add -1 roll
  93.       2 copy eq { cleartomark pop pop } { ] readonly .growput } ifelse
  94.     }
  95.     {        % Make a new entry.
  96.       mark 4 -1 roll ] readonly .growput
  97.     }
  98.    ifelse .setglobal
  99.  } bind def
  100.  
  101. % Parse a font file just enough to find the FontName or FontType.
  102. /.findfontvalue        % <file> <key> .findfontvalue <value> true
  103.             % <file> <key> .findfontvalue false
  104.             % Closes the file in either case.
  105.  { exch dup read not { -1 } if
  106.    2 copy unread 16#80 eq
  107.     { dup (xxxxxx) readstring pop pop }        % skip .PFB header
  108.    if
  109.         % Stack: key file
  110.     { dup token not { false exit } if        % end of file
  111.       dup /eexec eq { pop false exit } if    % reached eexec section
  112.       dup /Subrs eq { pop false exit } if    % Subrs without eexec
  113.       dup /CharStrings eq { pop false exit } if    % CharStrings without eexec
  114.       dup 3 index eq
  115.        { xcheck not { dup token exit } if }    % found key
  116.        { pop }
  117.       ifelse
  118.     } loop
  119.         % Stack: key file value true   (or)
  120.         % Stack: key file false
  121.    dup { 4 } { 3 } ifelse -2 roll closefile pop
  122.  } bind def
  123. /.findfontname
  124.  { /FontName .findfontvalue
  125.  } bind def
  126.  
  127. % If there is no FONTPATH, try to get one from the environment.
  128. NOFONTPATH { /FONTPATH () def } if
  129. /FONTPATH where
  130.  { pop }
  131.  { /FONTPATH (GS_FONTPATH) getenv not { () } if def }
  132. ifelse
  133. FONTPATH length 0 eq { (%END FONTPATH) .skipeof } if
  134. /FONTPATH [ FONTPATH .pathlist ] def
  135.  
  136. % Scan directories looking for plausible fonts.  "Plausible" means that
  137. % the file begins with %!PS-AdobeFont or %!FontType1, or with \200\001
  138. % followed by four arbitrary bytes and then either of these strings.
  139. % To speed up the search, we skip any file whose name appears in
  140. % the Fontmap (with any extension and upper/lower case variation) already,
  141. % and any file whose extension definitely indicates it is not a font.
  142. %
  143. % NOTE: The current implementation of this procedure is somewhat Unix/DOS-
  144. % specific.  It assumes that '/' and '\' are directory separators, and that
  145. % the part of a file name following the last '.' is the extension.
  146. %
  147. /.lowerstring        % <string> .lowerstring <lowerstring>
  148.  { 0 1 2 index length 1 sub
  149.     { 2 copy get dup 65 ge exch 90 le and
  150.        { 2 copy 2 copy get 32 add put }
  151.      if pop
  152.     }
  153.    for
  154.  } bind def
  155. /.splitfilename        % <dir.../base.extn> .basename <base> <extn>
  156.  {  { (/) search { true } { (\\) search } ifelse
  157.        { pop pop }
  158.        { exit }
  159.       ifelse
  160.     }
  161.    loop
  162.    dup { (.) search { pop pop } { exit } ifelse } loop
  163.    2 copy eq
  164.     { pop () }
  165.     { exch dup length 2 index length 1 add sub 0 exch getinterval exch }
  166.    ifelse
  167. % Following is debugging code.
  168. %   (*** Split => ) print 2 copy exch ==only ( ) print ==only
  169. %   ( ***\n) print flush
  170.  } bind def
  171. /.scanfontdict 1 dict def        % establish a binding
  172. /.scanfontbegin
  173.  {    % Construct the table of all file names already in Fontmap.
  174.    currentglobal true setglobal
  175.    .scanfontdict dup maxlength Fontmap length 2 add .max .setmaxlength
  176.    Fontmap
  177.     { exch pop
  178.        { dup type /stringtype eq
  179.       { .splitfilename pop =string copy .lowerstring cvn
  180.         .scanfontdict exch true put
  181.       }
  182.       { pop
  183.       }
  184.      ifelse
  185.        }
  186.       forall
  187.     }
  188.    forall
  189.    setglobal
  190.  } bind def
  191. /.scanfontskip mark
  192.         % Strings are converted to names anyway, so....
  193.   /afm true
  194.   /bat true
  195.   /c true
  196.   /cmd true
  197.   /com true
  198.   /dll true
  199.   /doc true
  200.   /drv true
  201.   /exe true
  202.   /fon true
  203.   /fot true
  204.   /h true
  205.   /o true
  206.   /obj true
  207.   /pfm true
  208.   /pss true        % Adobe Multiple Master font instances
  209.   /txt true
  210. .dicttomark def
  211. /.scan1fontstring 128 string def
  212. /.scanfontheaders [(%!PS-Adobe*) (%!FontType*)] def
  213. 0 .scanfontheaders { length max } forall 6 add    % extra for PFB header
  214. /.scan1fontfirst exch string def
  215. /.scanfontdir        % <dirname> .scanfontdir -
  216.  { currentglobal exch true setglobal
  217.    QUIET not { (Scanning ) print dup print ( for fonts...) print flush } if
  218.    (*) 2 copy .filenamedirseparator
  219.    dup (\\) eq { pop (\\\\) } if    % double \ for pattern match
  220.    exch concatstrings concatstrings
  221.    0 0 0 4 -1 roll    % found scanned files
  222.     {        % stack: <fontcount> <scancount> <filecount> <filename>
  223.       exch 1 add exch                   % increment filecount
  224.       dup .splitfilename .lowerstring
  225.         % stack: <fontcount> <scancount> <filecount+1> <filename>
  226.         %    <BASE> <ext>
  227.       .scanfontskip exch known exch .scanfontdict exch known or
  228.        { pop
  229.         % stack: <fontcount> <scancount> <filecount+1>
  230.        }
  231.        { 3 -1 roll 1 add 3 1 roll
  232.         % stack: <fontcount> <scancount+1> <filecount+1> <filename>
  233.      dup (r) { file } .internalstopped
  234.       { pop pop null ()
  235.         % stack: <fontcount> <scancount+1> <filecount+1> <filename>
  236.         %    null ()
  237.       }
  238.       {
  239.         % On some platforms, the file operator will open directories,
  240.         % but an error will occur if we try to read from one.
  241.         % Handle this possibility here.
  242.         dup .scan1fontfirst { readstring } .internalstopped
  243.          { pop pop () }
  244.          { pop }
  245.         ifelse
  246.         % stack: <fontcount> <scancount+1> <filecount+1>
  247.         %    <filename> <file> <header>
  248.       }
  249.      ifelse
  250.         % Check for PFB file header.
  251.      dup (\200\001????*) .stringmatch
  252.       { dup length 6 sub 6 exch getinterval }
  253.      if
  254.         % Check for font file headers.
  255.      false .scanfontheaders
  256.       { 2 index exch .stringmatch or
  257.       }
  258.      forall exch pop
  259.       {    % stack: <fontcount> <scancount+1> <filecount+1> <filename>
  260.         %    <file>
  261.         dup 0 setfileposition .findfontname
  262.          { dup Fontmap exch known
  263.         { pop pop
  264.         }
  265.         { exch copystring exch
  266.           DEBUG { ( ) print dup =only } if
  267.           1 index .definefontmap
  268.           .splitfilename pop true .scanfontdict 3 1 roll .growput
  269.             % Increment fontcount.
  270.           3 -1 roll 1 add 3 1 roll
  271.         }
  272.            ifelse
  273.          }
  274.          { pop
  275.          }
  276.         ifelse
  277.       }
  278.         % .findfontname will have done a closefile in the above case.
  279.       { dup null eq { pop } { closefile } ifelse pop
  280.       }
  281.      ifelse
  282.        }
  283.       ifelse
  284.     }
  285.    .scan1fontstring filenameforall
  286.    QUIET
  287.     { pop pop pop }
  288.     { ( ) print =only ( files, ) print =only ( scanned, ) print
  289.       =only ( new fonts.\n) print flush
  290.     }
  291.    ifelse
  292.    setglobal
  293.  } bind def
  294.  
  295. %END FONTPATH
  296.  
  297. % Create the dictionary that registers the .buildfont procedure (called by
  298. % definefont) for each FontType.
  299. /buildfontdict 20 dict def
  300.  
  301. % Register Type 3 fonts, which are always supported, for definefont.
  302. buildfontdict 3 /.buildfont3 cvx put
  303.  
  304. % Register Type 0 fonts if they are supported.  Strictly speaking,
  305. % we should do this in its own file (gs_type0.ps), but since this is
  306. % the only thing that would be in that file, it's simpler to put it here.
  307. /.buildfont0 where { pop buildfontdict 0 /.buildfont0 cvx put } if
  308.  
  309. % Define definefont.  This is a procedure built on a set of operators
  310. % that do all the error checking and key insertion.
  311. /.growfontdict
  312.  {    % Grow the font dictionary, if necessary, to ensure room for an
  313.     % added entry, making sure there is at least one slot left for FID.
  314.    dup maxlength 1 index length sub 2 lt
  315.     { dup dup wcheck
  316.        { .growdict }
  317.        { .growdictlength dict .copydict }
  318.       ifelse
  319.     }
  320.     { dup wcheck not { dup maxlength dict .copydict } if
  321.     }
  322.    ifelse
  323.  } bind def 
  324. /.completefont {
  325.   {        % Check for disabled platform fonts.
  326.       NOPLATFONTS
  327.        {    % Make sure we leave room for FID.
  328.      .growfontdict dup /ExactSize 0 put
  329.        }
  330.        {    % Hack: if the Encoding looks like it might be the
  331.         % Symbol or Dingbats encoding, load those now (for the
  332.         % benefit of platform font matching) just in case
  333.         % the font didn't actually reference them.
  334.      dup /Encoding get length 65 ge
  335.       { dup /Encoding get 64 get
  336.         dup /congruent eq { SymbolEncoding pop } if
  337.         /a9 eq { DingbatsEncoding pop } if
  338.       }
  339.      if
  340.        }
  341.       ifelse
  342.       dup /FontType get //buildfontdict exch get exec
  343.       DISKFONTS
  344.        { FontFileDirectory 2 index known
  345.       { dup /FontFile FontFileDirectory 4 index get .growput
  346.       }
  347.      if
  348.        }
  349.       if
  350.       readonly        % stack: name fontdict
  351.   } stopped { /invalidfont signalerror } if
  352. } bind odef
  353. /definefont
  354.  { .completefont
  355.         % If the current allocation mode is global, also enter
  356.         % the font in LocalFontDirectory.
  357.    .currentglobal
  358.     { //systemdict /LocalFontDirectory .knownget
  359.        { 2 index 2 index .growput }
  360.       if
  361.     }
  362.    if
  363.    dup .FontDirectory 4 -2 roll .growput
  364.  } odef
  365.  
  366. % Define a procedure for defining aliased fonts.
  367. % We can't just copy the font (or even use the same font unchanged),
  368. % because a significant number of PostScript files assume that
  369. % the FontName of a font is the same as the font resource name or
  370. % the key in [Shared]FontDirectory; on the other hand, some Adobe files
  371. % rely on the FontName of a substituted font *not* being the same as
  372. % the requested resource name.  We address this issue heuristically:
  373. % we substitute the new name iff the font name doesn't have MM in it.
  374. /.aliasfont        % <name> <font> .aliasfont <newFont>
  375.  { .currentglobal 3 1 roll dup .gcheck .setglobal
  376.    dup length 2 add dict
  377.    dup 3 -1 roll { 1 index /FID eq { pop pop } { put dup } ifelse } forall
  378.         % Stack: global fontname newfont newfont.
  379.         % We might be defining a global font whose FontName
  380.         % is a local string.  This is weird, but legal,
  381.         % and doesn't cause problems anywhere else:
  382.         % to avoid any possible problems in this case, do a cvn.
  383.         % We might also be defining (as an alias) a global font
  384.         % whose FontName is a local non-string, if someone passed a
  385.         % garbage value to findfont.  In this case, just don't
  386.         % call definefont at all.
  387.    2 index dup type /stringtype eq exch .gcheck or 1 index .gcheck not or
  388.     { 2 index =string cvs (MM) search
  389.        { pop pop pop pop
  390.        }
  391.        { /FontName exch dup type /stringtype eq { cvn } if put
  392.        }
  393.       ifelse
  394.         % Don't bind in definefont, since Level 2 redefines it.
  395.       //systemdict /definefont get exec
  396.     }
  397.     { .completefont pop exch pop
  398.     }
  399.    ifelse exch .setglobal
  400.  } odef        % so findfont will bind it
  401.  
  402. % Define .loadfontfile for loading a font.  If we recognize Type 1 and/or
  403. % TrueType fonts, gs_type1.ps and/or gs_ttf.ps will redefine this.
  404. /.loadfontfile { cvx exec } bind def
  405. /.loadfont
  406.  {        % Some buggy fonts leave extra junk on the stack,
  407.         % so we have to make a closure that records the stack depth
  408.         % in a fail-safe way.
  409.    /.loadfontfile cvx count 1 sub 2 packedarray cvx exec
  410.    count exch sub { pop } repeat
  411.  } bind def
  412.  
  413. % Find an alternate font to substitute for an unknown one.
  414. % We go to some trouble to parse the font name and extract
  415. % properties from it.  Later entries take priority over earlier.
  416. /.substitutefaces [
  417.     % Guess at suitable substitutions for random unknown fonts.
  418.   [(Grot) /Times]
  419.   [(Roman) /Times]
  420.   [(Book) /NewCenturySchlbk]
  421.     % If the family name appears in the font name,
  422.     % use a font from that family.
  423.   [(Arial) /Helvetica]
  424.   [(Avant) /AvantGarde]
  425.   [(Bookman) /Bookman]
  426.   [(Century) /NewCenturySchlbk]
  427.   [(Cour) /Courier]
  428.   [(Geneva) /Helvetica]
  429.   [(Helv) /Helvetica]
  430.   [(NewYork) /Times]
  431.   [(Pala) /Palatino]
  432.   [(Sans) /Helvetica]
  433.   [(Schlbk) /NewCenturySchlbk]
  434.   [(Serif) /Times]
  435.   [(Swiss) /Helvetica]
  436.   [(Times) /Times]
  437.     % Substitute for Adobe Multiple Master fonts.
  438.   [(Myriad) /Times]
  439.   [(Minion) /Helvetica]
  440.     % Condensed or narrow fonts map to the only narrow family we have.
  441.   [(Cond) /Helvetica-Narrow]
  442.   [(Narrow) /Helvetica-Narrow]
  443.     % If the font wants to be monospace, use Courier.
  444.   [(Monospace) /Courier]
  445.   [(Typewriter) /Courier]
  446. ] readonly def
  447. /.substituteproperties [
  448.   [(It) 1] [(Oblique) 1]
  449.   [(Bd) 2] [(Bold) 2] [(bold) 2] [(Demi) 2] [(Heavy) 2] [(Sb) 2]
  450. ] readonly def
  451. /.substitutefamilies mark
  452.   /AvantGarde
  453.     {/AvantGarde-Book /AvantGarde-BookOblique
  454.      /AvantGarde-Demi /AvantGarde-DemiOblique}
  455.   /Bookman
  456.     {/Bookman-Demi /Bookman-DemiItalic /Bookman-Light /Bookman-LightItalic}
  457.   /Courier
  458.     {/Courier /Courier-Oblique /Courier-Bold /Courier-BoldOblique}
  459.   /Helvetica
  460.     {/Helvetica /Helvetica-Oblique /Helvetica-Bold /Helvetica-BoldOblique}
  461.   /Helvetica-Narrow
  462.     {/Helvetica-Narrow /Helvetica-Narrow-Oblique
  463.      /Helvetica-Narrow-Bold /Helvetica-Narrow-BoldOblique}
  464.   /NewCenturySchlbk
  465.     {/NewCenturySchlbk-Roman /NewCenturySchlbk-Italic
  466.      /NewCenturySchlbk-Bold /NewCenturySchlbk-BoldItalic}
  467.   /Palatino
  468.     {/Palatino-Roman /Palatino-Italic /Palatino-Bold /Palatino-BoldItalic}
  469.   /Times
  470.     {/Times-Roman /Times-Italic /Times-Bold /Times-BoldItalic}
  471. .dicttomark readonly def
  472. /.substitutefont        % <fontname> .substitutefont <altname>
  473.  {    % Look for properties and/or a face name in the font name.
  474.     % If we find any, use Helvetica as the base font;
  475.     % otherwise, use the default font.
  476.     % Note that the "substituted" font name may be the same as
  477.     % the requested one; the caller must check this.
  478.    dup type dup /stringtype eq exch /nametype eq or
  479.     { dup length string cvs } { () } ifelse
  480.     {defaultfontname /Helvetica-Oblique /Helvetica-Bold /Helvetica-BoldOblique}
  481.    exch 0 exch    % stack: fontname facelist properties fontname
  482.     % Look for a face name.
  483.    .substitutefaces
  484.     { 2 copy 0 get search
  485.        { pop pop pop 1 get .substitutefamilies exch get
  486.      4 -1 roll pop 3 1 roll
  487.        }
  488.        { pop pop
  489.        }
  490.       ifelse
  491.     }
  492.    forall
  493.    .substituteproperties
  494.     { 2 copy 0 get search
  495.        { pop pop pop 1 get 3 -1 roll or exch }
  496.        { pop pop }
  497.       ifelse
  498.     }
  499.    forall pop get
  500.     % If SUBSTFONT is defined, use it.
  501.    /SUBSTFONT where
  502.     { pop pop /SUBSTFONT load cvn }
  503.     { exec }
  504.    ifelse
  505.     % Only accept fonts known in the Fontmap.
  506.    Fontmap 1 index known not { pop defaultfontname } if
  507.  } bind def
  508.  
  509. % If requested, make (and recognize) fake entries in FontDirectory for fonts
  510. % present in Fontmap but not actually loaded.  Thanks to Ray Johnston for
  511. % the idea behind this code.
  512. FAKEFONTS not { (%END FAKEFONTS) .skipeof } if
  513.  
  514. % We use the presence or absence of the FontMatrix key to indicate whether
  515. % a font is real or fake.  We must pop the arguments at the very end,
  516. % so that stack protection will be effective.
  517.  
  518. /definefont {        % <name> <font> definefont <font>
  519.   dup /FontMatrix known {
  520.     //definefont
  521.   } {
  522.     2 copy /FontName get findfont //definefont exch pop exch pop
  523.   } ifelse
  524. } bind odef
  525.  
  526. /scalefont {        % <font> <scale> scalefont <font>
  527.   1 index /FontMatrix known {
  528.     //scalefont
  529.   } {
  530.     1 index /FontName get findfont 1 index //scalefont
  531.     exch pop exch pop
  532.   } ifelse
  533. } bind odef
  534.  
  535. /makefont {        % <font> <matrix> makefont <font>
  536.   1 index /FontMatrix known {
  537.     //makefont
  538.   } {
  539.     1 index /FontName get findfont 1 index //makefont
  540.     exch pop exch pop
  541.   } ifelse
  542. } bind odef
  543.  
  544. /setfont {        % <font> setfont -
  545.   dup /FontMatrix known {
  546.     //setfont
  547.   } {
  548.     dup /FontName get findfont //setfont pop
  549.   } ifelse
  550. } bind odef
  551.  
  552. %END FAKEFONTS
  553.  
  554. % Define findfont so it tries to load a font if it's not found.
  555. % The Red Book requires that findfont be a procedure, not an operator,
  556. % but it still needs to restore the stacks reliably if it fails,
  557. % so we do all the work in an operator.
  558. /.findfont {
  559.   mark 1 index
  560.   //systemdict begin .dofindfont
  561.     % Define any needed aliases.
  562.   counttomark 1 sub { .aliasfont } repeat end
  563.   exch pop exch pop
  564. } odef
  565. /findfont {
  566.   .findfont
  567. } bind def
  568. % Check whether the font name we are about to look for is already on the list
  569. % of aliases we're accumulating; if so, cause an error.
  570. /.checkalias        % -mark- <alias1> ... <name> .checkalias <<same>>
  571.  { counttomark 1 sub -1 1
  572.     { index 1 index eq
  573.        { pop QUIET not
  574.       { (Unable to substitute for font.\n) print flush
  575.       } if
  576.      /findfont cvx /invalidfont signalerror
  577.        }
  578.       if
  579.     }
  580.    for
  581.  } bind def
  582. % Get a (non-fake) font if present in a FontDirectory.
  583. /.fontknownget        % <fontdir> <fontname> .fontknownget <font> true
  584.             % <fontdir> <fontname> .fontknownget false
  585.  { .knownget
  586.     { FAKEFONTS
  587.        { dup /FontMatrix known { true } { pop false } ifelse }
  588.        { true }
  589.       ifelse
  590.     }
  591.     { false
  592.     }
  593.    ifelse
  594.  } bind def
  595. % Do the work of findfont, including substitution, defaulting, and
  596. % scanning of FONTPATH.
  597. /.dofindfont        % <fontname> .dofindfont <font>
  598.  {  { .tryfindfont { exit } if
  599.             % We didn't find the font.  If we haven't scanned
  600.             % all the directories in FONTPATH, scan the next one now,
  601.             % and look for the font again.
  602.       null 0 1 FONTPATH length 1 sub
  603.        { FONTPATH 1 index get null ne { exch pop exit } if pop
  604.        }
  605.       for dup null ne
  606.        { dup 0 eq { .scanfontbegin } if
  607.      FONTPATH 1 index get .scanfontdir
  608.      FONTPATH exch null put
  609.             % Start over with an empty alias list.
  610.      counttomark 1 sub { pop } repeat
  611.      .dofindfont exit
  612.        }
  613.       if pop
  614.             % No luck, substitute for the font.
  615.       dup defaultfontname eq
  616.        { QUIET not
  617.       { (Unable to load default font ) print
  618.         dup =only (!  Giving up.\n) print flush
  619.       }
  620.      if /findfont cvx /invalidfont signalerror
  621.        }
  622.       if dup .substitutefont
  623.       2 copy eq { pop defaultfontname } if
  624.       .checkalias
  625.       QUIET not
  626.        { (Substituting font ) print dup =only ( for ) print
  627.      1 index =only (.\n) print flush
  628.        }
  629.       if
  630.     }
  631.    loop
  632.  } bind def
  633. % Try to find a font using only the present contents of Fontmap.
  634. /.tryfindfont        % <fontname> .tryfindfont <font> true
  635.             % <fontname> .tryfindfont false
  636.  { .FontDirectory 1 index .fontknownget
  637.     {            % Already loaded
  638.       exch pop true
  639.     }
  640.     { dup Fontmap exch .knownget not
  641.        {        % Unknown font name.  Look for a file with the
  642.             % same name as the requested font.
  643.      dup dup type /nametype eq { .namestring } if .loadfontloop
  644.        }
  645.        {        % Try each element of the Fontmap in turn.
  646.      false exch    % (in case we exhaust the list)
  647.             % Stack: fontname false fontmaplist
  648.      { exch pop
  649.        dup type /nametype eq
  650.         {            % Font alias
  651.           .checkalias .tryfindfont exit
  652.         }
  653.         { dup dup type dup /arraytype eq exch /packedarraytype eq or exch xcheck and
  654.            {        % Font with a procedural definition
  655.          exec        % The procedure will load the font.
  656.                 % Check to make sure this really happened.
  657.          .FontDirectory 1 index .knownget
  658.           { exch pop true exit }
  659.          if
  660.            }
  661.            {        % Font file name
  662.          .loadfontloop { true exit } if
  663.            }
  664.           ifelse
  665.         }
  666.        ifelse false
  667.      }
  668.      forall
  669.             % Stack: font true -or- fontname false
  670.      { true
  671.      }
  672.      {            % None of the Fontmap entries worked.
  673.                 % Try loading a file with the same name
  674.                 % as the requested font.
  675.        dup dup type /nametype eq { .namestring } if .loadfontloop
  676.      }
  677.     ifelse
  678.        }
  679.       ifelse
  680.     }
  681.    ifelse
  682.  } bind def
  683. % Attempt to load a font from a file.
  684. /.loadfontloop        % <filename> .loadfontloop <font> true
  685.             % <filename> .loadfontloop false
  686.  {            % See above regarding the use of 'loop'.
  687.  
  688.     {
  689.             % Is the font name a string?
  690.     dup type /stringtype ne
  691.      { QUIET not
  692.         { (Can't find font with non-string name: ) print dup =only (.\n) print flush
  693.         }
  694.        if pop false exit
  695.      }
  696.     if
  697.             % Can we open the file?
  698.     findlibfile not
  699.      { QUIET not
  700.         { (Can't find \(or can't open\) font file ) print dup print
  701.           (.\n) print flush
  702.         }
  703.        if pop false exit
  704.      }
  705.     if
  706.  
  707.             % Stack: fontname fontfilename fontfile
  708.     DISKFONTS
  709.      { .currentglobal true .setglobal
  710.        2 index (r) file
  711.        FontFileDirectory exch 5 index exch .growput
  712.        .setglobal
  713.      }
  714.     if
  715.     QUIET not
  716.      { (Loading ) print 2 index =only
  717.        ( font from ) print 1 index print (... ) print flush
  718.      }
  719.     if
  720.     % If LOCALFONTS isn't set, load the font into local or global
  721.     % VM according to FontType; if LOCALFONTS is set, load the font
  722.     % into the current VM, which is what Adobe printers (but not
  723.     % DPS or CPSI) do.
  724.     LOCALFONTS { false } { /setglobal where } ifelse
  725.      { pop /FontType .findfontvalue { 1 eq } { false } ifelse
  726.         % .setglobal, like setglobal, aliases FontDirectory to
  727.         % GlobalFontDirectory if appropriate.  However, we mustn't
  728.         % allow the current version of .setglobal to be bound in,
  729.         % because it's different depending on language level.
  730.        .currentglobal exch /.setglobal load exec
  731.         % Remove the fake definition, if any.
  732.        .FontDirectory 3 index .undef
  733.        1 index (r) file .loadfont .FontDirectory exch
  734.        /.setglobal load exec
  735.      }
  736.      { .loadfont .FontDirectory
  737.      }
  738.     ifelse
  739.         % Stack: fontname fontfilename fontdirectory
  740.     QUIET not
  741.      { //systemdict /level2dict known
  742.         { .currentglobal false .setglobal vmstatus
  743.           true .setglobal vmstatus 3 -1 roll pop
  744.           6 -1 roll .setglobal 5
  745.         }
  746.         { vmstatus 3
  747.         }
  748.        ifelse { =only ( ) print } repeat
  749.        (done.\n) print flush
  750.      } if
  751.  
  752.         % Check to make sure the font was actually loaded.
  753.     dup 3 index .fontknownget
  754.      { 4 1 roll pop pop pop true exit } if
  755.  
  756.         % Maybe the file had a different FontName.
  757.         % See if we can get a FontName from the file, and if so,
  758.         % whether a font by that name exists now.
  759.     exch (r) file .findfontname
  760.      { 2 copy .fontknownget
  761.         {    % Yes.  Stack: origfontname fontdirectory filefontname fontdict
  762.           3 -1 roll pop exch
  763.           QUIET
  764.            { pop
  765.            }
  766.            { (Using ) print =only
  767.              ( font for ) print 1 index =only
  768.              (.\n) print flush
  769.            }
  770.           ifelse true exit
  771.         }
  772.        if pop
  773.      }
  774.     if pop
  775.  
  776.         % The font definitely did not load correctly.
  777.     QUIET not
  778.      { (Loading ) print dup =only
  779.        ( font failed.\n) print flush
  780.      } if
  781.     false exit
  782.  
  783.     } loop        % end of loop
  784.  
  785.  } bind def
  786.  
  787. % Define a procedure to load all known fonts.
  788. % This isn't likely to be very useful.
  789. /loadallfonts
  790.  { Fontmap { pop findfont pop } forall
  791.  } bind def
  792.  
  793. % If requested, load all the fonts defined in the Fontmap into FontDirectory
  794. % as "fake" fonts i.e., font dicts with only FontName and FontType defined.
  795. % (We define FontType only to for the sake of some questionable code in the
  796. % Apple Printer Utility 2.0 font inquiry code.) We must ensure that this
  797. % happens in both global and local directories.
  798. /.definefakefonts
  799.     {
  800.     }
  801.     { (gs_fonts FAKEFONTS) VMDEBUG
  802.       2
  803.     { .currentglobal not .setglobal
  804.       Fontmap
  805.        { pop dup type /stringtype eq { cvn } if
  806.          .FontDirectory 1 index known not
  807.           { 2 dict dup /FontName 3 index put
  808.         dup /FontType 1 put
  809.             .FontDirectory 3 1 roll put
  810.           }
  811.           { pop
  812.           }
  813.          ifelse
  814.        }
  815.       forall
  816.        }
  817.       repeat
  818.     }
  819. FAKEFONTS { exch } if pop def        % don't bind, .current/setglobal get redefined
  820.  
  821. % Install initial fonts from Fontmap.
  822. /.loadinitialfonts
  823.  { NOFONTMAP not
  824.     { /FONTMAP where
  825.       { pop [ FONTMAP .pathlist ]
  826.          { dup VMDEBUG findlibfile
  827.         { exch pop .loadFontmap }
  828.         { /undefinedfilename signalerror }
  829.            ifelse
  830.          }
  831.       }
  832.       { LIBPATH
  833.          { defaultfontmap 2 copy .filenamedirseparator
  834.            exch concatstrings concatstrings dup VMDEBUG
  835.            (r) { file } .internalstopped
  836.         { pop pop } { .loadFontmap } ifelse
  837.          }
  838.       }
  839.      ifelse forall
  840.     }
  841.    if
  842.    .definefakefonts
  843.  } def            % don't bind, .current/setglobal get redefined
  844.  
  845. % ---------------- Synthetic font support ---------------- %
  846.  
  847. % Create a new font by modifying an existing one.  paramdict contains
  848. % entries with the same keys as the ones found in a Type 1 font;
  849. % it should also contain enough empty entries to allow adding the
  850. % corresponding non-overridden entries from the original font dictionary,
  851. % including FID.  If paramdict includes a FontInfo entry, this will
  852. % also override the original font's FontInfo, entry by entry;
  853. % again, it must contain enough empty entries.
  854.  
  855. % Note that this procedure does not perform a definefont.
  856.  
  857. /.makemodifiedfont    % <fontdict> <paramdict> .makemodifiedfont <fontdict'>
  858.  { exch
  859.     {            % Stack: destdict key value
  860.       1 index /FID ne
  861.        { 2 index 2 index known
  862.       {        % Skip fontdict entry supplied in paramdict, but
  863.             % handle FontInfo specially.
  864.         1 index /FontInfo eq
  865.          { 2 index 2 index get        % new FontInfo
  866.            1 index                % old FontInfo
  867.         {    % Stack: destdict key value destinfo key value
  868.           2 index 2 index known
  869.            { pop pop }
  870.            { 2 index 3 1 roll put }
  871.           ifelse
  872.         }
  873.            forall pop
  874.          }
  875.         if
  876.       }
  877.       {        % No override, copy the fontdict entry.
  878.         2 index 3 1 roll put
  879.         dup dup    % to match pop pop below
  880.       }
  881.      ifelse
  882.        }
  883.       if
  884.       pop pop
  885.     } forall
  886.  } bind def
  887.  
  888. % Make a modified font and define it.  Note that unlike definefont,
  889. % this does not leave the font on the operand stack.
  890.  
  891. /.definemodifiedfont    % <fontdict> <paramdict> .definemodifiedfont -
  892.  { .makemodifiedfont
  893.    dup /FontName get exch definefont pop
  894.  } bind def
  895.